#include "datacenter.h"

#include <QStandardPaths>
#include <QFile>
#include <QDir>
#include <QJsonDocument>
#include <QJsonObject>

namespace model
{
DataCenter* DataCenter::instance = nullptr;

DataCenter *DataCenter::getInstance()
{
    if (instance == nullptr)
        instance = new DataCenter();
    return instance;
}

DataCenter::DataCenter()
    : netClient(this)
{
    recentMessages = new QHash<QString, QList<Message>>();
    memberList = new QHash<QString, QList<UserInfo>>();
    unreadMessageCount = new QHash<QString, int>();

    loadDataFile();
}

DataCenter::~DataCenter()
{
    delete myself;
    delete friendList;
    delete chatSessionList;
    delete memberList;
    delete applyList;
    delete recentMessages;
    delete unreadMessageCount;
    delete searchrMessageResult;
    delete searchUserResult;
}

void DataCenter::initDataFile()
{
    // 构造出文件的路径
    QString basePath = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
    QString filePath = basePath + "/Chat_Client.json";
    LOG("filePath = ") << filePath;

    QDir dir;
    if (!dir.exists(basePath))
        dir.mkpath(basePath);

    // 把文件创建出来
    // 写
    QFile file(filePath);
    if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
    {
        LOG("打开文件失败!") << file.errorString();
        return;
    }
    QString data = "{\n\n}";
    file.write(data.toUtf8());
    file.close();
}

void DataCenter::savaDataFile()
{
    QString filePath = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation)
                       + "/Chat_Client.json";

    QFile file(filePath);
    if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
    {
        LOG("文件打开失败!") << file.errorString();
        return;
    }

    // 按照json格式来写入数据
    QJsonObject jsonObj;
    jsonObj["loginSessionId"] = loginSessionId;

    QJsonObject jsonUnread;
    for (auto it = unreadMessageCount->begin(); it != unreadMessageCount->end(); ++it)
    {
        jsonUnread[it.key()] = it.value();
    }
    jsonObj["unread"] = jsonUnread;

    // 将json写入文件
    QJsonDocument jsonDoc(jsonObj);
    QString s = jsonDoc.toJson();
    file.write(s.toUtf8());

    file.close();
}

// 加载文件 是在 DataCenter 被实例化时候，被调用执行的
void DataCenter::loadDataFile()
{
    QString filePath = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation)
                       + "/Chat_Client.json";

    QFileInfo fileInfo(filePath);
    if (!fileInfo.exists())
        initDataFile();

    // 读方式打开文件
    QFile file(filePath);
    if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
    {
        LOG("文件打开失败!") << file.errorString();
        return;
    }

    // 读取到文件对象 解析为 JSON 对象
    QJsonDocument jsonDoc = QJsonDocument::fromJson(file.readAll());
    if (jsonDoc.isNull())
    {
        LOG("解析 JSON 文件失败! JSON 文件格式有错误");
        file.close();
        return;
    }

    QJsonObject jsonObj = jsonDoc.object();
    this->loginSessionId = jsonObj["loginSessionId"].toString();
    LOG("loginSessionId = ") << this->loginSessionId;

    this->unreadMessageCount->clear();
    QJsonObject jsonUnread = jsonObj["unread"].toObject();
    for (auto it = jsonUnread.begin(); it != jsonUnread.end(); ++it)
    {
        this->unreadMessageCount->insert(it.key(), it.value().toInt());
    }

    file.close();
}

void DataCenter::clearUnread(const QString &chatSessionId)
{
    (*unreadMessageCount)[chatSessionId] = 0;

    // 保存结果
    savaDataFile();
}

void DataCenter::addUnread(const QString &chatSessionId)
{
    ++(*unreadMessageCount)[chatSessionId];

    // 保存结果
    savaDataFile();
}

int DataCenter::getUnread(const QString &chatSessionId)
{
    return (*unreadMessageCount)[chatSessionId];
}

void DataCenter::initWebsocket()
{
    netClient.initWebsocket();
}



void DataCenter::getMyselfAsync()
{
    // DataCenter 只负责处理数据
    netClient.getMyself(loginSessionId);
}

UserInfo *DataCenter::getMyself()
{
    return myself;
}

void DataCenter::resetMyself(std::shared_ptr<bite_im::GetUserInfoRsp> resp)
{
    if (myself == nullptr)
        myself = new UserInfo();

    const bite_im::UserInfo& userInfo = resp->userInfo();
    myself->load(userInfo);
}

void DataCenter::getFriendListAsync()
{
    netClient.getFriendList(loginSessionId);
}

QList<UserInfo> *DataCenter::getFriendList()
{
    return friendList;
}

void DataCenter::resetFriendList(std::shared_ptr<bite_im::GetFriendListRsp> resp)
{
    if (friendList == nullptr)
        friendList = new QList<UserInfo>();
    friendList->clear();

    QList<bite_im::UserInfo>& friendListPB = resp->friendList();
    for (auto& f : friendListPB)
    {
        UserInfo userInfo;
        userInfo.load(f);
        friendList->push_back(userInfo);
    }
}

void DataCenter::getChatSessionListAsync()
{
    netClient.getChatSessionList(loginSessionId);
}

QList<ChatSessionInfo> *DataCenter::getChatSessionList()
{
    return chatSessionList;
}

void DataCenter::resetChatSessionList(std::shared_ptr<bite_im::GetChatSessionListRsp> resp)
{
    if (chatSessionList == nullptr)
        chatSessionList = new QList<ChatSessionInfo>();
    chatSessionList->clear();

    auto& chatSessionListPB = resp->chatSessionInfoList();
    for (auto& c : chatSessionListPB)
    {
        ChatSessionInfo chatSessionInfo;
        chatSessionInfo.load(c);
        chatSessionList->push_back(chatSessionInfo);
    }
}

void DataCenter::getApplyListAsync()
{
    netClient.getApplyList(loginSessionId);
}

QList<UserInfo> *DataCenter::getApplyList()
{
    return applyList;
}

void DataCenter::resetApplyList(std::shared_ptr<bite_im::GetPendingFriendEventListRsp> resp)
{
    if (applyList == nullptr)
        applyList = new QList<UserInfo>();
    applyList->clear();

    auto& eventList = resp->event();
    for (auto& event : eventList)
    {
        UserInfo userInfo;
        userInfo.load(event.sender());
        applyList->push_back(userInfo);
    }
}

void DataCenter::getRecentMessageListAsync(const QString &chatSessionId, bool updateUI)
{
    netClient.getRecentMessageList(loginSessionId, chatSessionId, updateUI);
}

QList<Message> *DataCenter::getRecentMessageList(const QString &chatSessionId)
{
    if (!recentMessages->contains(chatSessionId))
        return nullptr;
    return &(*recentMessages)[chatSessionId];
}

void DataCenter::resetRecentMessageList(const QString &chatSessionId, std::shared_ptr<bite_im::GetRecentMsgRsp> resp)
{
    // 拿到 chatSession 对应的消息列表 并清空
    QList<Message>& messageList = (*recentMessages)[chatSessionId];
    messageList.clear();

    // 遍历响应结果的列表
    for (auto& m : resp->msgList())
    {
        Message message;
        message.load(m);

        messageList.push_back(message);
    }
}

void DataCenter::sendTextMessageAsync(const QString &chatSessionId, const QString &content)
{
    netClient.sendMessage(loginSessionId, chatSessionId, MessageType::TEXT_TYPE, content.toUtf8(), "");
}

void DataCenter::sendImageMessageAsync(const QString &chatSessionId, const QByteArray &content)
{
    netClient.sendMessage(loginSessionId, chatSessionId, MessageType::IMAGE_TYPE, content, "");
}

void DataCenter::sendFileMessageAsync(const QString &chatSessionId, const QString &fileName, const QByteArray &content)
{
    netClient.sendMessage(loginSessionId, chatSessionId, MessageType::FILE_TYPE, content, fileName);
}

void DataCenter::sendSpeechMessageAsync(const QString &chatSessionId, const QByteArray &content)
{
    netClient.sendMessage(loginSessionId, chatSessionId, MessageType::SPEECH_TYPE, content, "");
}

void DataCenter::changeNicknameAsync(const QString &nickname)
{
    netClient.changeNickname(loginSessionId, nickname);
}

void DataCenter::resetNickname(const QString &nickname)
{
    if (myself == nullptr)
        return;
    myself->nickname = nickname;
}

void DataCenter::changeDescriptionAsync(const QString &desc)
{
    netClient.changeDescription(loginSessionId, desc);
}

void DataCenter::resetDescription(const QString &desc)
{
    if (myself == nullptr)
        return;
    myself->description = desc;
}

void DataCenter::getVerifyCodeAsync(const QString &phone)
{
    netClient.getVerifyCode(phone);
}

void DataCenter::resetVerifyCodeId(const QString &verifyCodeId)
{
    this->currentVerifyCodeId = verifyCodeId;
}

const QString &DataCenter::getVerifyCodeId()
{
    return currentVerifyCodeId;
}

void DataCenter::changePhoneAsync(const QString &phone, const QString &verifyCodeId, const QString &verifyCode)
{
    netClient.changePhone(loginSessionId, phone, verifyCodeId, verifyCode);
}

void DataCenter::resetPhone(const QString &phone)
{
    if (myself == nullptr)
        return;
    myself->phone = phone;
}

void DataCenter::changeAvatarAsync(const QByteArray &imageBytes)
{
    netClient.changeAvatar(loginSessionId, imageBytes);
}

void DataCenter::resetAvatar(const QByteArray &avatar)
{
    if (myself == nullptr)
        return;
    myself->avatar = makeIcon(avatar);
}

void DataCenter::deleteFriendAsync(const QString &userId)
{
    netClient.deleteFriend(loginSessionId, userId);
}

void DataCenter::removeFriend(const QString &userId)
{
    if (friendList == nullptr || chatSessionList == nullptr)
        return;
    friendList->removeIf([=](const UserInfo& userInfo){
        return userInfo.userId == userId;
    });

    // 会话列表
    chatSessionList->removeIf([=](const ChatSessionInfo& chatSessionInfo){
        if (chatSessionInfo.userId == "")
        {
            // 群聊不受影响
            return false;
        }
        if (chatSessionInfo.userId == userId)
        {
            // 正在选中的会话内容清空
            if (chatSessionInfo.chatSessionId == this->currentChatSessionId)
            {
                emit this->clearCurrentSession();
            }
            return true;
        }


        return false;
    });
}

void DataCenter::addFriendApplyAsync(const QString &userId)
{
    netClient.addFriendApply(loginSessionId, userId);
}

void DataCenter::acceptFriendApplyAsync(const QString &userId)
{
    netClient.acceptFriendApply(loginSessionId, userId);
}

UserInfo DataCenter::removeFromApplyList(const QString &userId)
{
    if (applyList == nullptr)
        return UserInfo();
    for (auto it = applyList->begin(); it != applyList->end(); ++it)
    {
        if (it->userId == userId)
        {
            // 备份删除对象
            UserInfo toDelete = *it;
            applyList->erase(it);
            return toDelete;
        }
    }
    return UserInfo();
}

void DataCenter::rejectFriendApplyAsync(const QString &userId)
{
    netClient.rejectFriendApply(loginSessionId, userId);
}

void DataCenter::createGroupChatSessionAsync(const QList<QString> &userIdList)
{
    netClient.createGroupChatSession(loginSessionId, userIdList);
}

void DataCenter::getMemberListAsync(const QString &chatSessionId)
{
    netClient.getMemberList(loginSessionId, chatSessionId);
}

QList<UserInfo> *DataCenter::getMemberList(const QString& chatSessionId)
{
    if (!this->memberList->contains(chatSessionId))
        return nullptr;

    return &(*this->memberList)[chatSessionId];
}

void DataCenter::resetMemberList(const QString &chatSessionId, const QList<bite_im::UserInfo> &memberList)
{
    // 根据 chatSessionId, 这个 key, 得到对应的 value (QList)
    QList<UserInfo>& currentMemberList = (*this->memberList)[chatSessionId];
    currentMemberList.clear();

    for (const auto& m : memberList) {
        UserInfo userInfo;
        userInfo.load(m);
        currentMemberList.push_back(userInfo);
    }
}

ChatSessionInfo *DataCenter::findChatSessionById(const QString &chatSessionId)
{
    if (chatSessionList == nullptr)
        return nullptr;
    for (auto& info : *chatSessionList)
    {
        if (info.chatSessionId == chatSessionId)
            return &info;
    }
    return nullptr;
}

ChatSessionInfo *DataCenter::findChatSessionByUserId(const QString &userId)
{
    if (chatSessionList == nullptr)
        return nullptr;
    for (auto& info : *chatSessionList)
    {
        if (info.userId == userId)
            return &info;
    }
    return nullptr;
}

void DataCenter::topChatSessionInfo(const ChatSessionInfo &chatSessionInfo)
{
    // 把这个元素从列表中找到 删除 并且重新插入到头部中
    if (chatSessionList == nullptr)
        return;

    // 1. 把这个元素从列表中找到
    auto it = chatSessionList->begin();
    for (; it != chatSessionList->end(); ++it)
    {
        if (it->chatSessionId == chatSessionInfo.chatSessionId)
            break;
    }

    if (it == chatSessionList->end())
        return;

    // 2. 备份元素 删除元素
    ChatSessionInfo backup = chatSessionInfo;
    chatSessionList->erase(it);

    // 3. 头插备份元素
    chatSessionList->push_front(backup);
}

UserInfo* DataCenter::findFriendById(const QString &userId)
{
    if (this->friendList == nullptr)
        return nullptr;
    for (auto& f : *friendList)
    {
        if (f.userId == userId)
            return &f;
    }
    return nullptr;
}

void DataCenter::setCurrentChatSessionId(const QString &chatSessionId)
{
    this->currentChatSessionId = chatSessionId;
}

const QString &DataCenter::getCurrentChatSessionId()
{
    return this->currentChatSessionId;
}

void DataCenter::addMessage(const Message &message)
{
    QList<Message>& messageList = (*recentMessages)[message.chatSessionId];
    messageList.push_back(message);
}

void DataCenter::searchUserAsync(const QString &searchKey)
{
    netClient.searchUser(loginSessionId, searchKey);
}

QList<UserInfo> *DataCenter::getSearchUserResult()
{
    return searchUserResult;
}

void DataCenter::resetSearchUserResult(const QList<bite_im::UserInfo> &userList)
{
    if (searchUserResult == nullptr)
        searchUserResult = new QList<UserInfo>();
    searchUserResult->clear();

    for (const auto& u : userList)
    {
        UserInfo userInfo;
        userInfo.load(u);
        searchUserResult->push_back(userInfo);
    }
}

void DataCenter::searchMessageAysnc(const QString &searchKey)
{
    netClient.searchMessage(loginSessionId, this->currentChatSessionId, searchKey);
}

void DataCenter::searchMsgByTimeAsync(const QDateTime &begTime, const QDateTime &endTime)
{
    netClient.searchMsgByTime(loginSessionId, this->currentChatSessionId, begTime, endTime);
}

QList<Message> *DataCenter::getSearchMessageResult()
{
    return searchrMessageResult;
}

void DataCenter::resetSearchMsgResult(const QList<bite_im::MessageInfo> &msgList)
{
    if (this->searchrMessageResult == nullptr)
        this->searchrMessageResult = new QList<Message>();
    this->searchrMessageResult->clear();

    for (const auto& m : msgList)
    {
        Message message;
        message.load(m);
        searchrMessageResult->push_back(message);
    }
}

void DataCenter::userLoginAsync(const QString &username, const QString& password)
{
    netClient.userLogin(username, password);
}

void DataCenter::resetLoginSessionId(const QString &loginSessionId)
{
    this->loginSessionId = loginSessionId;

    savaDataFile();
}

void DataCenter::userRegisterAsync(const QString &username, const QString &password)
{
    netClient.useRegister(username, password);
}

void DataCenter::phoneLoginAsync(const QString &phone, const QString &verifyCode)
{
    netClient.phoneLogin(phone, this->currentVerifyCodeId, verifyCode);
}

void DataCenter::phoneRegisterAsync(const QString &phone, const QString &verifyCode)
{
    netClient.phoneRegister(phone, this->currentVerifyCodeId, verifyCode);
}

void DataCenter::getSingleFileAsync(const QString &fileId)
{
    netClient.getSingleFile(loginSessionId, fileId);
}

void DataCenter::speechConvertTextAsync(const QString& fileId, const QByteArray &content)
{
    netClient.speechConvertText(loginSessionId, fileId, content);
}







}
